﻿/*
 *  Copyright (C) 2010 by Benjamin Nolmans <benjamin.nolmans@gmail.com>
 *  and Barbara Post <postb99@gmail.com>
 *  Copyright (C) 2010 by Barbara Post postb99@gmail.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
using System;
using System.IO;
using OsamesFrameworkCore.Logging;
using OsamesFrameworkCore.Xml;
using OsamesFrameworkCore.Xml.Types;

namespace OsamesFrameworkCore.Configuration
{
    public class CoreConfiguration : ILoggable
    {
        #region attributes, constants and static strings

        /// <summary>
        /// Define default theme if none or custom file not found
        /// </summary>
        private const string CST_STR_DEFAULT_THEME = @"\default\default.css";

        /// <summary>
        /// Retrive the application domain path and add the themes directory
        /// </summary>
        private static readonly string _strApplicationGlobalThemesPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "themes");

        /// <summary>
        /// Dictionary to keep configuration values.
        /// </summary>
        private XmlDictionaryContainer _xdcOsamesCoreConfiguration = new XmlDictionaryContainer();

        /// <summary>
        /// CoreConfiguration singleton.
        /// </summary>
        private static CoreConfiguration _ccCoreConfigurationSingleton;

        /// <summary>
        /// Lock object used to instantiate singleton.
        /// </summary>
        private static readonly object _oLock = new object();

        /// <summary>
        /// State of application configuration logging overriding (no override, override, logging off).
        /// </summary>
        private LogOverridingState _eLogOverridingState;
        /// <summary>
        /// Set to true once global overriding log level has been determined.
        /// </summary>
        private bool _bGlobalOverridingLogLevelDetermined;
        /// <summary>
        /// Global overriding log level. Equal to LogLevel.NotSet or another log level value.
        /// </summary>
        private LogLevel _eGlobalOverridingLogLevel;
        
        #endregion

        #region static properties
        /// <summary>
        /// Property creates a singleton or returns it.
        /// </summary>
        public static CoreConfiguration Instance
        {
            get
            {
                lock (_oLock)
                {
                    // instantiates singleton if null, and returns it
                    return _ccCoreConfigurationSingleton ?? (_ccCoreConfigurationSingleton = new CoreConfiguration());
                }
            }
        }

        /// <summary>
        /// Definition of plugins directory path.        
        /// </summary>
        public static string PluginsDirectoryPath
        {
            get
            {
                LoggerService.LogToOutput("Current Domaine Base Directory: " + AppDomain.CurrentDomain.BaseDirectory);
                return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
            }
        }

        /// <summary>
        /// Definition of plugins directory path.        
        /// </summary>
        public static string CoreConfigurationPath
        {
            get
            {
                LoggerService.LogToOutput("Current Domaine Base Directory: " + AppDomain.CurrentDomain.BaseDirectory);
                return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "OsamesConfiguration.xml");
            }
        }

        #endregion

        #region non-static properties

        /// <summary>
        /// Acccess to dictionary which keeps configuration values.
        /// </summary>
        public XmlDictionaryContainer XdcOsamesCoreConfiguration
        {
            get { return _xdcOsamesCoreConfiguration; }
            private set { _xdcOsamesCoreConfiguration = value; }
        }

        /// <summary>
        /// Global overriding of LogLevel definitions.
        /// If equal to LogLevel.NotSet, no overriding.
        /// Only determined when LogOverrideState is "yes".
        /// </summary>
        public LogLevel GlobalOverridingLogLevel
        {
            get
            {
                if (_bGlobalOverridingLogLevelDetermined)
                    return _eGlobalOverridingLogLevel;

                if(LogOverridingState == LogOverridingState.Yes)
                {
                    string strValue = _xdcOsamesCoreConfiguration.FindValue("sectionLogOverride", "logLevel");
                    // If we cannot parse the value in core config, let's remain with no override.
                    Enum.TryParse(strValue, true, out _eGlobalOverridingLogLevel);
                }
                _bGlobalOverridingLogLevelDetermined = true;
                return _eGlobalOverridingLogLevel;
            }
        }

        /// <summary>
        /// State of application configuration logging overriding (no override, override, logging off).
        /// </summary>
        public LogOverridingState LogOverridingState
        {
            get
            {
                if (_eLogOverridingState == LogOverridingState.Undefined)
                {
                    string strValue = _xdcOsamesCoreConfiguration.FindValue("sectionLogOverride", "override");
                    // If we cannot parse the value in core config, let's remain with no override.
                    if (!Enum.TryParse(strValue, true, out _eLogOverridingState))
                        _eLogOverridingState = LogOverridingState.No;
                }
                return _eLogOverridingState;
            }
        }

        #endregion

        #region constructor and methods

        /// <summary>
        /// Private constructor (singleton pattern).
        /// </summary>
        private CoreConfiguration()
        {
            
        }
        /// <summary>
        /// Loads core configuration XML file.
        /// </summary>
        /// <param name="configurationfilepath_"></param>
        public void LoadCoreConfiguration(string configurationfilepath_)
        {
            XmlConfigurationLoader.ProcessConfigurationFile(configurationfilepath_,out _xdcOsamesCoreConfiguration); 
           // TODO make TU work ValidateCoreConfiguration();
           
        }
      
        /// <summary>
        /// Logging facility.
        /// </summary>
        /// <param name="eLogLevel_"></param>
        /// <param name="strMessage_"></param>
        /// <param name="strMessageDetails_">Optional array of message details. In this case, strMessage_ parameter contains placeholders, each matching a value in strMessageDetails_</param>
        public void Log(LogLevel eLogLevel_, string strMessage_, object[] strMessageDetails_ = null)
        {
            LoggerService.Log(this, eLogLevel_, strMessage_, strMessageDetails_);
        }

        /// <summary>
        /// Logging facility.
        /// </summary>
        /// <param name="eLogLevel_">Osames log level</param>
        /// <param name="strMessage_">Message</param>
        /// <param name="ex_">Exception we will log message and stack trace of</param>
        public void Log(LogLevel eLogLevel_, string strMessage_, Exception ex_)
        {
            LoggerService.Log(this, eLogLevel_, strMessage_, ex_);
        }
        /// <summary>
        /// Ensures that core configuration has correct values, set default values if needed.
        /// </summary>
        private void ValidateCoreConfiguration()
        {
            if (String.IsNullOrEmpty(_xdcOsamesCoreConfiguration.FindValue("sectionWebTheme", "themePath")))
                _xdcOsamesCoreConfiguration.SetValue("sectionWebTheme", "themePath", _strApplicationGlobalThemesPath);

            if (String.IsNullOrEmpty(_xdcOsamesCoreConfiguration.FindValue("sectionWebTheme", "themeName")))
                _xdcOsamesCoreConfiguration.SetValue("sectionWebTheme", "themeName", CST_STR_DEFAULT_THEME);
        }

        #endregion

        /*
      
        /// <summary>
        /// Theme used by application for html renderer
        /// </summary>
        public string ApplicationThemeName { get; set; }

        /// <summary>
        /// Required values validation etc.
        /// </summary>
        public void Validate()
        {
            if (string.IsNullOrEmpty(PluginPath))
                throw new Exception("PluginPath is required");

            if (string.IsNullOrEmpty(ApplicationThemeName))
                ApplicationThemeName = _strApplicationGlobalThemesPath + CST_STR_DEFAULT_THEME;

            string strTmp = _strApplicationGlobalThemesPath + ApplicationThemeName;
            if (!File.Exists(strTmp))
            {
                Log(LogLevel.Warn, "File Theme not found. \r Loading Default Theme!");
                ApplicationThemeName = _strApplicationGlobalThemesPath + CST_STR_DEFAULT_THEME;
            }
        }
        */

    }
}